<script>
import scVideo from '@/components/scVideo';
// 预览组件以及样式
import VMdPreview from '@kangc/v-md-editor/lib/preview';
// import createCopyCodePlugin from '@kangc/v-md-editor/lib/plugins/copy-code/index';
import createCopyCodePlugin from '@kangc/v-md-editor/lib/plugins/copy-code/index';
import '@kangc/v-md-editor/lib/plugins/copy-code/copy-code.css';

import '@kangc/v-md-editor/lib/style/preview.css';
// VuePress主题以及样式（这里也可以选择github主题）
import vuepressTheme from '@kangc/v-md-editor/lib/theme/vuepress.js';
import '@kangc/v-md-editor/lib/theme/style/vuepress.css';
// Prism
import Prism from 'prismjs';
// 代码高亮
import 'prismjs/components/prism-json';
import { CircleClose, DocumentCopy, Refresh, PictureFilled, VideoPlay, VideoPause } from '@element-plus/icons-vue';
import ChatTextLoading from './ChatTextLoading';

// 选择使用主题
VMdPreview.use(vuepressTheme, {
  Prism,
});
VMdPreview.use(createCopyCodePlugin());

export default {
  name: 'ChatMessageRow',
  components: {
    CircleClose,
    Refresh,
    PictureFilled,
    VMdPreview,
    vuepressTheme,
    ChatTextLoading,
    createCopyCodePlugin,
    DocumentCopy,
    VideoPlay,
    VideoPause,
    scVideo,
  },
  props: {
    message: {
      type: Object,
      required: true,
    },
    avatar: String,
  },
  data() {
    return {
      logo: 'http://192.168.10.105:18080/logo.png',
      toolbar: {
        customToolbar: {
          icon: 'toolbar图标类名',
          title: 'hover时显示的标题',
          action(editor) {
            // toolbar点击时触发的函数
            console.log(editor);
          },
        },
      },
      userNameF: '',
      showTools: false,

      minIndex: 0,
      maxIndex: 1,
      activeIndex: 0, // 当前显示元素的索引
      maxDisplay: 3, // 最多显示的元素数量
      webSearchCount: 0,

      minSourceFileIndex: 0,
      maxSourceFileIndex: 1,
      activeSourceFileIndex: 0, // 当前显示元素的索引
      sourceFileCount: 0,

      audioPlaying: false,
      currentMessage: null,
      lastCurrentPlayingIndex: 0,
      currentMarkdownContent: '',
    };
  },
  mounted() {
    var userInfo = this.$TOOL.data.get('USER_INFO');

    this.userNameF = userInfo.userName.substring(0, 1);
    if (this.message.webSearch) {
      this.webSearchCount = this.message.webSearch.length - 1;
    }
    this.maxIndex = this.minIndex + this.maxDisplay - 1;

    if (this.message.sourceFiles) {
      this.sourceFileCount = this.message.sourceFiles.length - 1;
    }
    this.maxSourceFileIndex = this.maxSourceFileIndex + this.maxDisplay - 1;

    // this.currentMessage = JSON.parse(JSON.stringify(this.message)); //this.templateData是父组件传递的对象
    this.currentMessage = this.message;
    // Object.assign(this.currentMessage, this.message);
  },
  updated() {},
  methods: {
    /**
     * 加载图片
     */
    loadImage() {
      this.$emit('loadIsOk', true);
    },

    handleCopyCodeSuccess(code) {
      var that = this;
      this.$nextTick(() => {
        const textarea = document.createElement('textarea');
        textarea.value = code;
        document.body.appendChild(textarea);
        textarea.select();
        document.execCommand('Copy');
        document.body.removeChild(textarea);
        that.$message.success('已复制到剪切板');
      });
    },
    copyContent() {
      this.handleCopyCodeSuccess(this.message.content);
    },
    copyContentToInput(val) {
      this.$emit('callback', val);
      this.showTools = false;
    },
    playVideo(id) {
      if (!this.message.content) return;
      var that = this;
      this.currentMessage = JSON.parse(JSON.stringify(this.message)); //this.templateData是父组件传递的对象
      this.$nextTick(() => {
        if (window.speechSynthesis.speaking) {
          window.speechSynthesis.cancel();
        }
        if (this.audioPlaying) {
          this.audioPlaying = false;
          return;
        }

        this.currentMarkdownContent = '';
        this.lastCurrentPlayingIndex = 0;
        window.speechSynthesis.resume(); // 为了防止在暂停状态下转语音，调用前设置继续播放
        // 设置播放
        var textArea = document.getElementById(id);
        var range = document.createRange();
        range.selectNodeContents(textArea);
        var speech = new SpeechSynthesisUtterance();
        speech.text = this.message.content; // 内容
        speech.lang = 'zh-cn'; // 语言
        // speech.voiceURI = 'Microsoft Huihui - Chinese (Simplified, PRC)'; // 声音和服务
        //  speech.voiceURI = 'Google 普通话（中国大陆）';
        //
        const synth = window.speechSynthesis;
        const voices = synth.getVoices();
        console.log('voices', voices);
        // speech.voice = voices[2];
        speech.voiceURI = 'Microsoft Yaoyao - Chinese (Simplified, PRC)';

        // eslint-disable-next-line no-irregular-whitespace
        speech.volume = 0.7; // 声音的音量区间范围是​​0​​​到​​1默认是​​1​​
        // eslint-disable-next-line no-irregular-whitespace
        speech.rate = 1; // 语速，数值，默认值是​​1​​​，范围是​​0.1​​​到​​10​​​，表示语速的倍数，例如​​2​​表示正常语速的两倍
        // eslint-disable-next-line no-irregular-whitespace
        speech.pitch = 1; // 表示说话的音高，数值，范围从​​0​​​（最小）到​​2​​​（最大）。默认值为​​1​​。
        // 监听播放
        speech.onboundary = function (event) {
          //
          console.log(event);
          //   if (event.charLength <= 0)
          //     return;
          //   console.log("lastCurrentPlayingIndex :", that.lastCurrentPlayingIndex, ",charIndex", event.charIndex);
          //   if (that.lastCurrentPlayingIndex != 0 && that.lastCurrentPlayingIndex > event.charIndex) {
          //     return;
          //   }
          //   // charIndex charLength
          //   // let start = that.message.content.slice(0, event.charIndex);
          //   let end = that.message.content.slice(event.charIndex + event.charLength);

          //   let val = that.message.content.slice(event.charIndex, event.charIndex + event.charLength);
          //   console.log("val ,", val);
          //   let replacement = `<span class="playingText" style="color: #0099ff !important">${val}</span>`;
          //   //   let replacement = `<font color=#008000>${val}</font>`;
          //   // let replacement = val;
          //   // <font color=#008000>我是绿色</font>

          //   // 去增加忽略的
          //   if (that.lastCurrentPlayingIndex < event.charIndex) {
          //     let tval = that.message.content.slice(that.lastCurrentPlayingIndex,
          //       event.charIndex
          //     );
          //     console.log('tval', tval);
          //     tval = tval.replace("\n", "<br/>");
          //     that.currentMarkdownContent += tval;

          //     console.log(that.currentMarkdownContent);
          //   }
          //   that.currentMessage.content = that.currentMarkdownContent + replacement + end;

          //   that.currentMarkdownContent += replacement;
          //   that.lastCurrentPlayingIndex = event.charIndex + event.charLength;
        };

        // 播放结束
        speech.onend = function (event) {
          //
          console.log(event);
          that.audioPlaying = false;
        };
        // 播放出错
        speech.onerror = function (event) {
          //
          console.log(event);
          that.audioPlaying = false;
        };
        // 播放开始
        speech.onstart = function (event) {
          //
          console.log(event);
          that.audioPlaying = true;
        };
        // 播放重置
        speech.onresume = function (event) {
          //
          console.log(event);
          that.audioPlaying = false;
        };
        window.speechSynthesis.speak(speech);
      });
    },
    onMouseEnter() {
      this.showTools = true;
    },
    onMouseLeave() {
      setTimeout(() => {
        this.showTools = false;
      }, 2000);
    },
    preHandle() {
      if (!this.message.webSearch) return;
      this.activeIndex = this.activeIndex - 1;
      // 识别 active index 的位置
      if (this.activeIndex >= 0) {
        this.minIndex = this.activeIndex;
        this.maxIndex = this.minIndex + this.maxDisplay - 1;
      }
    },
    nextHandle() {
      if (!this.message.webSearch) return;
      this.activeIndex = this.activeIndex + 1;
      // 识别 active index 的位置
      if (this.activeIndex >= 0) {
        this.minIndex = this.activeIndex;
        this.maxIndex = this.minIndex + this.maxDisplay - 1;
      }
    },
    openWeb(item) {
      window.open(item.link, '_blank');
    },
    preSourceFileHandle() {
      if (!this.message.sourceFiles) return;
      this.activeSourceFileIndex = this.activeSourceFileIndex - 1;
      // 识别 active index 的位置
      if (this.activeSourceFileIndex >= 0) {
        this.minSourceFileIndex = this.activeSourceFileIndex;
        this.maxSourceFileIndex = this.minSourceFileIndex + this.maxDisplay - 1;
      }
    },
    nextSourceFileHandle() {
      if (!this.message.sourceFiles) return;
      this.activeSourceFileIndex = this.activeSourceFileIndex + 1;
      // 识别 active index 的位置
      if (this.activeSourceFileIndex >= 0) {
        this.minSourceFileIndex = this.activeSourceFileIndex;
        this.maxSourceFileIndex = this.minSourceFileIndex + this.maxDisplay - 1;
      }
    },
  },
};
</script>
<template>
  <div :class="['message-row', message.role === 'user' ? 'right' : 'left']">
    <!-- 消息展示，分为上下，上面是头像，下面是消息 -->
    <div class="row">
      <!-- 头像， -->
      <div class="avatar-wrapper">
        <el-avatar :size="30" class="avatar" shape="square">{{ currentMessage && currentMessage.role === 'user' ? userNameF : 'AI' }}</el-avatar>
      </div>
      <!-- 发送的消息或者回复的消息 -->
      <div class="message">
        <!-- 预览模式，用来展示markdown格式的消息 -->
        <!-- ref="preview" -->

        <div
          :class="['markdown-body', currentMessage && currentMessage.role === 'user' ? 'markdown-body-user' : 'markdown-body-answer']"
          v-on:mouseenter="onMouseEnter"
          v-on:mouseleave="onMouseLeave"
        >
          <div class="message-images" v-if="message.image">
            <el-image
              class="message-image-item"
              :src="message.image"
              alt="无法预览"
              :hide-on-click-modal="true"
              fit="contain"
              :zoom-rate="1.0"
              :preview-src-list="[message.image]"
            >
              <template #error>
                <div class="image-slot">
                  <el-icon :size="20">
                    <PictureFilled />
                  </el-icon>
                </div>
              </template>
            </el-image>
          </div>
          <div class="message-videos" v-if="message.videos">
            <div
              class="message-videos-wrapper"
              style="
                border-radius: 20px;
                display: block;
                height: 280px;
                width: 500px;
                margin-top: 20px;
                margin-bottom: 20px;
                margin-left: 20px;
                margin-right: 20px;
              "
              v-for="(item, index) in message.videos"
              :key="index"
            >
              <sc-video
                :src="item.url"
                :options="{
                  poster: item.cover_image_url,
                  pip: true,
                  loop: true,
                }"
              ></sc-video>
            </div>
          </div>

          <v-md-preview
            :id="message.messageId"
            :text="currentMessage && currentMessage.content"
            v-if="currentMessage && currentMessage.content"
            @copy-code-success="handleCopyCodeSuccess"
          ></v-md-preview>

          <!-- 如果消息的内容为空则显示加载动画 -->
          <ChatTextLoading v-if="!message.finish"></ChatTextLoading>

          <!--  web 搜索的链接  -->
          <div class="message-web-search" v-if="message.webSearch && message.finish">
            <div class="sites-cited-list-container">
              <div
                class="site-card"
                @click="openWeb(item)"
                v-for="(item, index) in message.webSearch"
                :key="index"
                v-show="index <= maxIndex && index >= minIndex"
              >
                <div class="site-description">
                  {{ item.title }}
                </div>
                <div class="site-info">
                  <div
                    class="site-icon"
                    :style="{
                      backgroundImage: `url('${item.icon}')`,
                    }"
                  ></div>
                  <div class="site-name">
                    {{ item.media }}
                  </div>
                </div>
              </div>

              <div class="left-block" v-show="activeIndex > 0"></div>
              <div class="left-btn" @click="preHandle" v-show="activeIndex > 0"></div>
              <div class="right-block" v-show="maxIndex < webSearchCount"></div>
              <div class="right-btn" @click="nextHandle" v-show="maxIndex < webSearchCount"></div>
            </div>
          </div>

          <!--  source file 搜索的链接  -->
          <div class="source-file-search" v-if="message.sourceFiles && message.finish">
            <div class="sites-cited-list-container">
              <div
                class="site-card"
                v-for="(item, index) in message.sourceFiles"
                :key="index"
                v-show="index <= maxSourceFileIndex && index >= minSourceFileIndex"
              >
                <div class="site-description">
                  {{ item }}
                </div>
              </div>

              <div class="left-block" v-show="activeSourceFileIndex > 0"></div>
              <div class="left-btn" @click="preSourceFileHandle" v-show="activeSourceFileIndex > 0"></div>
              <div class="right-block" v-show="maxSourceFileIndex < sourceFileCount"></div>
              <div class="right-btn" @click="nextSourceFileHandle" v-show="maxSourceFileIndex < sourceFileCount"></div>
            </div>
          </div>
        </div>
      </div>
      <!-- 工具栏 -->
      <div class="markdown-tools" :class="{ 'markdown-tools-visibility': !showTools }">
        <!-- <div class="tool-item" v-show="message.role == 'user'">
          <el-tooltip placement="top">
            <template #content> 复制入框 </template>
            <el-icon :size="20" @click="copyContentToInput(message.content)">
              <DocumentCopy />
            </el-icon>
          </el-tooltip>
        </div> -->
        <div class="tool-item" v-if="message.role !== 'user' && message.content">
          <el-tooltip placement="top">
            <template #content> 点击可复制 </template>
            <el-icon :size="20" @click="copyContent">
              <DocumentCopy />
            </el-icon>
          </el-tooltip>
        </div>
        <div class="tool-item" v-if="message.role !== 'user'">
          <el-tooltip placement="top">
            <template #content> 重新生成 </template>
            <el-icon :size="20" @click="copyContent">
              <Refresh />
            </el-icon>
          </el-tooltip>
        </div>
        <div class="tool-item" :class="{ 'audio-playing': audioPlaying }" v-if="message.role !== 'user' && message.content">
          <el-tooltip placement="top">
            <template #content> 语音播放 </template>
            <el-icon :size="20" @click="playVideo(message.messageId)">
              <VideoPause v-if="audioPlaying" />
              <VideoPlay v-else />
            </el-icon>
          </el-tooltip>
        </div>
      </div>
    </div>
  </div>
</template>
<style lang="scss" scoped>
.message-row {
  display: flex;
  overflow-x: auto;

  &.right {
    // 消息显示在右侧
    justify-content: flex-end;

    .row {
      // 头像也要靠右侧
      .avatar-wrapper {
        display: flex;
        justify-content: flex-end;
      }
    }
  }

  // 默认靠左边显示
  .row {
    .avatar-wrapper {
      .avatar {
        box-shadow: 20px 20px 20px 3px rgba(0, 0, 0, 0.03);
        margin-bottom: 10px;
      }
    }

    .message {
      font-size: 14px;
      //   padding: 1.5px;
      // 限制消息展示的最大宽度
      max-width: 100%;
      // 圆润一点
      border-radius: 10px;
      // 给消息框加一些描边，看起来更加实一些，要不然太扁了轻飘飘的。
      //   border: 1px solid rgba(black, 0.1);
      border: 1px solid #dedede;
      background-color: rgba(0, 0, 0, 0.05);
      // 增加一些阴影看起来更加立体
      box-shadow: 20px 20px 20px 1px rgba(0, 0, 0, 0.01);

      // web 搜索的返回
      .message-web-search {
        padding: 5px 24px;

        .link-card {
          max-width: 154px;
        }
      }
    }
    // source file 搜索的返回
    .source-file-search {
      padding: 5px 24px;

      .link-card {
        max-width: 154px;
      }
    }
    .markdown-body .image-slot {
      display: flex;
      justify-content: center;
      align-items: center;
      width: 100%;
      height: 100%;
      background: var(--el-fill-color-light);
      color: var(--el-text-color-secondary);
      font-size: 30px;
    }

    .markdown-tools {
      margin-top: 10px;
      cursor: pointer;
      display: flex;
      /* align-items: end; */
      justify-content: right;

      .tool-item {
        width: 40px;
        height: 34px;

        align-items: center;

        display: flex;
        justify-content: center;
        border-radius: 5px;

        background-color: var(--el-bg-color);

        &:hover {
          background-color: var(--el-text-color-disabled);
        }
      }
    }
  }
}

.sites-cited-list-container {
  display: flex;
  gap: 8px;
  align-items: center;
  position: relative;

  .site-card {
    display: flex;
    flex: 0 1 auto;
    padding: 10px 12px;
    flex-direction: column;
    gap: 6px;
    border-radius: 8px;
    background: var(--bg_grey_1, #f6f7f9);
    width: 180px;
    box-sizing: border-box;

    &:hover {
      cursor: pointer;
    }

    .site-description {
      display: -webkit-box;
      -webkit-box-orient: vertical;
      -webkit-line-clamp: 2;
      overflow: hidden;
      color: var(--txt_icon_black_1, #1a2029);
      text-overflow: ellipsis;
      font-family: PingFang SC;
      font-size: 12px;
      font-style: normal;
      font-weight: 400;
      line-height: 20px;
      height: 40px;
      word-break: break-word;
    }

    .site-info {
      display: flex;
      align-items: center;
      gap: 4px;

      .site-icon {
        width: 12px;
        height: 12px;
        background-repeat: no-repeat;
        background-size: cover;
        border-radius: 7px;
        flex: 0 0 12px;
      }

      .site-name {
        overflow: hidden;
        color: var(--txt_icon_grey_5, #838a95);
        text-overflow: ellipsis;
        font-family: PingFang SC;
        font-size: 10px;
        font-style: normal;
        font-weight: 400;
        line-height: 14px;
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 1;
        flex: 0 1 auto;
        word-break: break-word;
      }
    }
  }

  .left-block {
    position: absolute;
    width: 80px;
    height: 78px;
    background: linear-gradient(180deg, hsla(0, 0%, 100%, 0) 11.6%, #fff 92.28%);
  }

  .left-btn {
    width: 24px;
    height: 24px;
    background-repeat: no-repeat;
    background-size: cover;
    background-image: url();
    position: absolute;
    left: -12px;
  }

  .right-block {
    right: -12px;
    transform: rotate(-90deg);
  }

  .right-btn {
    width: 24px;
    height: 24px;
    background-repeat: no-repeat;
    background-size: cover;
    background-image: url();
    position: absolute;
    right: -12px;
  }
}

.audio-playing {
  background-color: var(--el-color-primary) !important;
}

.playingText {
  color: #0099ff !important;
}
.message-image-item {
  border-radius: 8px;
  display: block;
  height: 270px;
  width: 270px;
  margin-top: 20px;
  margin-bottom: 20px;
  margin-left: 20px;
  margin-right: 20px;
}
.markdown-tools-visibility {
  visibility: hidden;
}
// 调整markdown组件的一些样式，deep可以修改组件内的样式，正常情况是scoped只能修改本组件的样式。
:deep(.vuepress-markdown-body) {
  font-size: 14px !important;
  line-height: unset;
  background-color: transparent;
}

:deep(.vuepress-markdown-body:not(.custom)) {
  padding: 1rem 1.5rem !important;
}

:deep(.el-image-viewer__img) {
  width: 40% !important;

  height: auto !important;
}
:deep(.link-card) {
  .el-card__body {
    padding: 2px !important;
  }
}

:deep(.xgplayer-skin-default.xgplayer .xgplayer-ended .xgplayer-replay) {
  -o-object-fit: fill;
  object-fit: fill;
  border-radius: 14px;
}
:deep(.xgplayer-skin-default video) {
  -o-object-fit: fill;
  object-fit: fill;
  border-radius: 14px;
}

:deep(.sc-video) {
  -o-object-fit: fill;
  object-fit: fill;
  border-radius: 14px;
}
:deep(.xgplayer-skin-default .xgplayer-poster) {
  -o-object-fit: fill;
  object-fit: fill;
  border-radius: 14px;
}
:deep(.xgplayer-skin-default .xgplayer-replay) {
  -o-object-fit: fill;
  object-fit: fill;
  border-radius: 14px;
}
// .xgplayer.xgplayer-ended
:deep(.xgplayer-skin-default .xgplayer-controls) {
  -o-object-fit: fill;
  object-fit: fill;
  border-radius: 14px;
}
:deep(.xgplayer-skin-default .xgplayer-enter) {
  -o-object-fit: fill;
  object-fit: fill;
  border-radius: 14px;
}
:deep(.xgplayer-controls) {
  -o-object-fit: fill;
  object-fit: fill;
  border-radius: 14px;
}

.markdown-body-user {
  background-color: #e7f8ff;
}
.markdown-body-answer {
  //   background-color: rgba(0, 0, 0, 0.05);
}
</style>
